<!--
表单项组件
todo 值照常返回，并返回扩展值
-->
<template>
  <a-form-item v-if="show === undefined || show === true" v-bind="param">
    <!--自动完成-->
    <a-auto-complete
      v-if="param?.type == 'auto-complete'"
      v-model:value="val"
      v-bind="param?.params"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      :filter-option="filterOption"
      @select="handlerChange"
      @search="handlerSearch"
    />
    <!--级联选择-->
    <a-cascader
      v-if="param.type == 'cascader'"
      v-model:value="val"
      :show-search="{ filter }"
      v-bind="param?.params"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handleCascaderChange"
    />
    <!--多选框 单选-->
    <a-checkbox
      v-if="param?.type === 'checkbox' && !param?.params?.checkboxGroup"
      v-model:checked="val"
      v-bind="param?.params"
      :disabled="param?.disabled"
      :placeholder="param?.placeholder"
      @change="handlerChange($event.target.checked)"
      >{{ param?.name }}</a-checkbox
    >
    <!--多选框 复选-->
    <template v-else-if="param?.type === 'checkbox' && param?.params?.checkboxGroup">
      <a-checkbox v-model:checked="state.checkAll" :indeterminate="state.indeterminate" @change="onCheckAllChange">
        全选
      </a-checkbox>
      <a-divider />
      <a-checkbox-group
        v-bind="param?.params?.checkboxGroup"
        v-model:value="val"
        :placeholder="param?.placeholder"
        :disabled="param?.disabled"
        @change="handlerChange"
      />
    </template>
    <!-- 输入框 -->
    <a-input
      v-if="param?.type == 'input' && !param?.params?.type"
      v-model:value="val"
      allow-clear
      v-bind="param?.params"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handlerChange($event.target.value)"
    />
    <!--文本域输入框-->
    <a-textarea
      v-if="param?.type == 'input' && param?.params?.type === 'textarea'"
      v-bind="param?.params"
      v-model:value="val"
      allow-clear
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handlerChange($event.target.value)"
    />
    <!--搜索输入框-->
    <a-input-search
      v-if="param?.type == 'input' && param?.params?.type === 'search'"
      v-model:value="val"
      allow-clear
      v-bind="param?.params"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @search="$emit('extraUpdate', param.name, $event)"
      @change="handlerChange($event.target.value)"
    />
    <!--密码输入框-->
    <a-input-password
      v-if="param?.type == 'input' && param?.params?.type === 'password'"
      v-model:value="val"
      allow-clear
      v-bind="param?.params"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handlerChange($event.target.value)"
    />
    <!--数字输入框-->
    <a-input-number
      v-if="param.type == 'input-number'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!-- 选择器  -->
    <a-select
      v-if="param?.type == 'select'"
      v-model:value="val"
      show-search
      allow-clear
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--提及-->
    <a-mentions
      v-if="param.type == 'mentions'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
      @select="onSelect"
    >
      <a-mentions-option v-for="(item, index) in param?.params?.options" :key="index" :value="item.value">{{
        item.label
      }}</a-mentions-option>
    </a-mentions>
    <!--单选框-->
    <a-radio-group
      v-if="param.type == 'radio'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event.target.value)"
    />
    <!--评分-->
    <a-rate
      v-if="param.type == 'rate'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--滑动输入条-->
    <a-slider
      v-if="param.type == 'slider'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--开关-->
    <a-switch
      v-if="param.type == 'switch'"
      v-model:checked="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--穿梭框-->
    <a-transfer
      v-if="param.type == 'transfer'"
      v-bind="param?.params"
      v-model:target-keys="targetKeys"
      v-model:selected-keys="selectedKeys"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handleChange"
      @selectChange="handleSelectChange"
    />
    <!--树选择-->
    <a-tree-select
      v-if="param.type == 'tree-select'"
      v-bind="param?.params"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handlerChange($event)"
    >
    </a-tree-select>
    <!--日期选择框-->
    <a-date-picker
      v-if="param.type == 'date-picker'"
      v-model:value="val"
      :locale="locale"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @panelChange="handlerChange($event.value)"
      @change="handlerChange($event)"
    />
    <!--范围选择框-->
    <a-range-picker
      v-if="param.type == 'range-picker'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      :locale="locale"
      @panelChange="handlerChange($event.value)"
      @change="handlerChange($event)"
    />
    <!--时间选择器-->
    <a-time-picker
      v-if="param.type == 'time-picker'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--时间范围选择器-->
    <a-time-range-picker
      v-if="param.type == 'time-range-picker'"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
    <!--文件上传组件-->
    <base-upload
      v-if="param.type == 'upload'"
      v-bind="param?.params"
      v-model:value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      @change="handlerChange($event)"
    />
    <!--富文本编辑器-->
    <BaseWangEditor
      v-if="param.type == 'editor'"
      v-model:value="val"
      :value="val"
      :placeholder="param?.placeholder"
      :disabled="param?.disabled"
      v-bind="param?.params"
      @change="handlerChange($event)"
    />
  </a-form-item>
</template>

<script lang="ts" setup>
import BaseWangEditor from '@/components/base/base-editor/BaseWangEditor.vue'
import locale from 'ant-design-vue/es/date-picker/locale/zh_CN'
import dayjs, { Dayjs } from 'dayjs'
import 'dayjs/locale/zh-cn'
dayjs.locale('zh-cn')
import { watch, onMounted, ref, defineEmits, defineProps, withDefaults, reactive } from 'vue'
import type { ShowSearchType } from 'ant-design-vue/es/cascader'
import { TreeSelect } from 'ant-design-vue'
import {
  AutoCompleteParams,
  BaseFieldNames,
  CheckBoxParams,
  BaseType,
  FormItemParams,
  FormItemTypeEnum,
  SelectParams,
  ValueOptions,
  CascaderParams,
  TransferParams,
} from '@/components/base/form-item/props'
import type { Rule } from 'ant-design-vue/es/form'
export interface FormItem {
  // 表单项类型
  type: FormItemTypeEnum
  // 表单项配置参数
  params?: FormItemParams
  // 表单域 model 字段，在使用 validate、resetFields 方法的情况下，该属性是必填的
  name: string
  // 表单项绑定值(查询、修改时显示用)
  value: BaseType
  // 标签名
  label?: string
  // 表单验证规则
  rules?: object | Rule[]
  // 当某一规则校验不通过时，是否停止剩下的规则的校验。
  validateFirst?: boolean
  // 标签文本对齐方式
  labelAlign?: 'left' | 'right'
  // 是否必填，如不设置，则会根据校验规则自动生成
  required?: boolean
  // 提示信息，如不设置，则会根据校验规则自动生成
  placeholder?: string
  // 是否必填，如不设置，则会根据校验规则自动生成
  help?: string
  // 是否禁用
  disabled?: boolean
  // 列偏移
  wrapperCol?: { offset: number; span: number }
  // label 标签布局
  labelCol?: { offset: number; span: number }
  // 配合 validateStatus 属性使用，展示校验状态图标，建议只配合 Input 组件使用
  hasFeedback?: boolean
  // 额外的提示信息，和 help 类似，当需要错误信息和提示文案同时出现时，可以使用这个。
  extra?: string
  // 配合 label 属性使用，表示是否显示 label 后面的冒号
  colon?: boolean
  // 是否显示
  show?: boolean
}
const param = withDefaults(defineProps<FormItem>(), {
  show: true,
})
// 组件类的值
const val = ref<BaseType>()
// 选择的键
const selectedKeys = ref<BaseType>([])
const targetKeys = ref<BaseType>([])
onMounted(() => {
  val.value = param.value
  selectedKeys.value = targetKeys.value = param.value
})
watch(param, (newVal) => {
  val.value = newVal.value
  selectedKeys.value = targetKeys.value = val.value
})
export interface SearchValue {
  // 键
  key: string
  // 值
  value: any
  // 类型
  type: FormItemTypeEnum
}
// 表单项改变事件
const emit = defineEmits<{
  // 更新值的回调事件
  (e: 'update:value', value: BaseType): void
  // 搜索值改变事件
  (e: 'change', val: SearchValue): void
  // 扩展更新事件
  (e: 'extraUpdate', key: string, value: BaseType, extraValue?: BaseType): void
}>()
/////////////自动完成////////////////
// 过滤选项
const filterOption = (input: string, option: ValueOptions) => {
  return option.value.toUpperCase().indexOf(input.toUpperCase()) >= 0
}
// 搜索改变时
const handlerSearch = (searchText: string) => {
  emit(
    'extraUpdate',
    param.name,
    searchText,
    searchText
      ? (param?.params as AutoCompleteParams).options?.filter(
          (val) => val.value.toUpperCase().indexOf(searchText.toUpperCase()) != -1,
        )
      : [],
  )
}
/////////////////////////////

/////////////多选框////////////////
const state = reactive({
  indeterminate: true,
  checkAll: false,
  checkedList: [],
})
/**
 * 全选改变时
 * @param e
 */
const onCheckAllChange = (e: any) => {
  Object.assign(state, {
    checkedList: e.target.checked ? (param?.params as CheckBoxParams)?.checkboxGroup?.options || [] : [],
    indeterminate: false,
  })
}
watch(
  () => state.checkedList,
  (value) => {
    val.value = state.checkedList
    updateCheckState(value)
  },
)

/**
 * 复选框改变更新事件
 * @param value
 */
function updateCheckState(value: Array<any>) {
  const params = param?.params as CheckBoxParams
  if (params.checkboxGroup && params.checkboxGroup.options) {
    state.indeterminate = !!value.length && value.length < params.checkboxGroup.options.length
    state.checkAll = value.length === params.checkboxGroup.options.length
  }
}
/////////////////////////////

/////////////提及////////////////
const onSelect = (option: BaseFieldNames) => {
  emit('extraUpdate', param.name, val.value, option)
}
/////////////////////////////

/////////////选择框////////////////
/**
 * 更新选择框的值
 * @param value
 */
function updateSelectValue(value: BaseType) {
  const params = param?.params as SelectParams
  // 如果需要将标签和值都返回，则需要对数据值做进一步的处理，以扩展值返回
  if (params.labelInValue === true) {
    // 将扩展值返回
    emit('extraUpdate', param.name, val.value, value)
  }
}
/////////////////////////////

/////////////穿梭框////////////////
const handleChange = (nextTargetKeys: string[], direction: string, moveKeys: string[]) => {
  handlerChange(nextTargetKeys)
}
const handleSelectChange = (sourceSelectedKeys: string[], targetSelectedKeys: string[]) => {
  emit('extraUpdate', param.name, val.value, {
    sourceSelectedKeys,
    targetSelectedKeys,
  })
}
/////////////////////////////
/**
 * 表单项改变(todo 一般值改变都是走的这个方法)
 * @param value 值
 */
function handlerChange(value: BaseType) {
  // todo 部分组件可能没有update:value事件，这时候就需要我们手动更新了
  val.value = value
  emit('update:value', value)
  // 复选框改变内部处理事件
  if (param.type === FormItemTypeEnum.CHECKBOX) {
    updateCheckState(val.value as Array<any>)
  }
  // 选择框
  if (param.type === FormItemTypeEnum.SELECT || param.type === FormItemTypeEnum.TREE_SELECT) {
    updateSelectValue(value)
  }
  emit('change', { key: param.name, value: value, type: param.type })
}

/**
 * 级联改变
 * @param value 当前值
 * @param selectedOptions 节点链
 */
function handleCascaderChange(value: Array<string | number>, selectedOptions: any) {
  emit('update:value', value)
  emit('extraUpdate', param.name, value, selectedOptions)
}
// 级联可搜索
const filter: ShowSearchType['filter'] = (inputValue, path) => {
  return path.some((option) => {
    if (option.label) {
      return option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
    }
    if (option.name) {
      return option.name.toLowerCase().indexOf(inputValue.toLowerCase()) > -1
    }
    return []
  })
}
</script>

<style scoped lang="scss">
:deep(.ant-select) {
  min-width: 150px;
}
:deep(.ant-input-number) {
  width: 100% !important;
}
:deep(.ant-select-selection-item) {
  line-height: 28px !important;
}
</style>
